/*
============================================================================
 Name        : dd_ini_reader.c
 Author      : Jian
 Version     :
 Copyright   : GPL
 Description : dd_ini_reader.c - source file
============================================================================
*/

/* INCLUDE FILES */
#include "dd_ini_reader.h"
#include "sd_platform.h"
#include "dd_log.h"

#define __INI_BUFFER_SIZE (1024 * 20)
#define __INI_MAX_KEY     100


typedef struct {
    char  buffer[__INI_BUFFER_SIZE + 10 + 1] ;
    char* keys[__INI_MAX_KEY];
    char* values[__INI_MAX_KEY];
    int   keyCount;
} SNmsIniReader;


static SNmsIniReader* iniReader = NULL ;


static int _remove_comment(const char* start, const char* end1, const char* end2) 
{
    char* cursor = iniReader->buffer;
    char* bufEnd = cursor + strlen(iniReader->buffer) ;
    char* commentStart = NULL ;
    char* commentEnd = NULL ;
    
    int         endLen = 0 ;

    while(1) {
        commentStart = strstr(cursor, start) ;
        if (!commentStart) 
            break ;

        commentEnd = strstr(commentStart, end1) ;
        endLen = strlen(end1) ;

        if (!commentEnd && end2) {
            commentEnd = strstr(commentStart, end2) ;
            endLen = strlen(end2) ;
        }            

        if (!commentEnd) { 
            dd_log_warn("error to find comment end, start:%s, end1:%s, end2:%s", start, end1, end2 ? end2 : "null") ;
            return -1 ;
        }

        memmove(commentStart, commentEnd + endLen, bufEnd - (commentEnd + endLen) + 1) ;
    }

    return 0 ;
}


static void _parser_file() 
{
    char*       cursor = iniReader->buffer;
    const char* lineBreakStr = "\r\n";
    const char* blankStr = " \t";
    char*       lineBreakPos1 = NULL ;
    char*       lineBreakPos2 = NULL ;
    char*       equalPos = NULL ;
    char*       keyStartPos = NULL ;
    char*       keyEndPos = NULL ;
    char*       valuePos = NULL ;
    char*       endOfLine = NULL;
    int         i = 0;
    
    if (_remove_comment("/*", "*/", NULL) < 0)
        return ;

   if (_remove_comment("//", "\n", "\r") < 0) 
       return ;

    while ('\0' != *cursor) {

        /* skip linebreak and empty char */
        if (NULL != strchr(lineBreakStr, *cursor) || NULL != strchr(blankStr, *cursor)) {
            ++cursor;
            continue;
        }
        
        lineBreakPos1 = strchr(cursor, '\r');
        lineBreakPos2 = strchr(cursor, '\n');

        endOfLine = NULL;

        if (lineBreakPos1 == NULL || lineBreakPos2 == NULL)
            endOfLine = lineBreakPos1 < lineBreakPos2 ? lineBreakPos2 : lineBreakPos1;	
        else
            endOfLine = lineBreakPos1 > lineBreakPos2 ? lineBreakPos2 : lineBreakPos1;

        if (!endOfLine)
            return;

        *endOfLine = '\0';

        if ('=' == *cursor) {
            cursor = endOfLine + 1;
            continue;
        }
        /*
        comment = strchr(cursor, chComment);
        if (NULL != comment)
            *comment = '\0';
            */

        equalPos = strchr(cursor, '=');
        /* skip if line does not contain a pair Key = Value */
        if (NULL == equalPos) {
            cursor = endOfLine + 1;
            continue;
        }

        /* Key */
        keyStartPos = cursor;
        keyEndPos = equalPos - 1;
        while (strchr(blankStr, *keyEndPos) && keyEndPos > cursor)
            --keyEndPos;
        ++keyEndPos;
        *keyEndPos = '\0';


        /* Value */
        cursor = equalPos + 1;
        if ('\0' != *cursor && NULL != strchr(blankStr, *cursor))
            ++cursor;

        valuePos = cursor;

        cursor = endOfLine + 1;

        /* Insert into array if the key is unique (case-insensitive) */
        for (i = 0; i < iniReader->keyCount; i++) {
            if (dd_strcasecmp(iniReader->keys[i], keyStartPos) == 0) {
                break;
            }
        }

        if (i == iniReader->keyCount) {
            iniReader->keys[iniReader->keyCount]   = keyStartPos;
            iniReader->values[iniReader->keyCount] = valuePos;
            ++iniReader->keyCount;

            if (iniReader->keyCount == __INI_MAX_KEY)
                break;
        }
    }	
}


static void _init()
{
    sd_file* file = 0 ;
    int      readed = 0 ;
    char     fileName[DD_MAX_FILE_NAME_LEN + 1] = {0} ;
    int      fileSize = 0 ;
    
    iniReader = (SNmsIniReader*)dd_malloc(sizeof(SNmsIniReader)) ;

    __DD_CHECK_MEM(iniReader, sizeof(SNmsIniReader), return) ;

    sd_get_ini_file(fileName) ;

    if (fileName[0] == 0 || !sd_is_file_exist((const DD_UTF8*)fileName)) 
        return ;

    file = sd_file_open((const DD_UTF8*)fileName, DD_FILE_READ) ;

    if (file == NULL)  return;

    memset(iniReader, 0, sizeof(SNmsIniReader)) ;
    
    readed = sd_file_read(file, iniReader->buffer, __INI_BUFFER_SIZE) ;

    if (readed > 0) {
        strcat(iniReader->buffer, "\r\n") ;
        _parser_file(iniReader->buffer);
    }

    if (file)  sd_file_close(file) ;
}


const char* dd_ini_read_key(const char* key) 
{
    int i = 0 ;

    __DD_ASSERT_DEFENSE(key, return NULL) ;

    if (!iniReader) { 
        _init() ;
        if (!iniReader) return NULL ;
    }

    for (i = 0; i < iniReader->keyCount ; i++) {
        if (dd_strcasecmp(iniReader->keys[i], key) == 0)
            return iniReader->values[i];
    }

    return NULL;
}


void dd_ini_reload() 
{
    if (iniReader)  dd_free(iniReader) ;
    iniReader = NULL ;

    _init() ;
}


/* End of File */
